﻿namespace NetFx.SMIL.References
{
  using System;
  using System.Text;
  using System.Collections;
  using System.Collections.Generic;

  using System.Reflection;
  using System.Reflection.Emit;
  using System.Runtime.InteropServices;

  using System.Diagnostics;
  using System.Diagnostics.CodeAnalysis;
  using System.Diagnostics.SymbolStore;
  using System.Security;
  using System.Security.Permissions;

  using NetFx.MSIL;

  /// <summary>
  /// 对方法的引用。
  /// </summary>
  public class MethodRef:MemberRef
  {
    #region Statics
    public new static MethodRef it()
    {
      return new MethodRef();
    }
    public static MethodRef of(MethodBase method)
    {
      return new MethodRef(method);
    }
    public static MethodRef of(string identifier, params ParameterRef[] parameters)
    {
      return new MethodRef(identifier, parameters);
    }
    #endregion
    #region Fields
    /// <summary>
    /// 引用方法时需要的参数。
    /// </summary>
    /// <remarks>
    /// 如果引用不直接来自于MethodBase，
    /// 那么需要记录参数以帮助查找MethodBase。
    /// 如果引用来自MethodBase，则参数将自动建立。
    /// </remarks>
    protected List<ParameterRef> parameters = null;
    #endregion
    #region Properties
    /// <summary>
    /// 获取引用类型（为模块）。
    /// </summary>
    public override DefType ReflectionType
    {
      get { return DefType.Method; }
    }
    /// <summary>
    /// 获取反射信息。
    /// </summary>
    public new virtual MethodBase ReflectInfo
    {
      get
      {
        return this.referenced as MethodBase;
      }
    }
    public override bool HasReflectInfo
    {
      get
      {
        return this.ReflectInfo != null;
      }
    }

    /// <summary>
    /// 获取引用方法的参数列表。
    /// </summary>
    public virtual List<ParameterRef> Parameters
    {
      get
      {
        return this.parameters == null ?
          this.parameters = new List<ParameterRef>() :
          this.parameters;
      }
    }
    public virtual int ParametersCount
    {
      get
      {
        return this.parameters != null ? this.parameters.Count : 0;
      }
    }
    public virtual Type ReturnType
    {
      get
      {
        MethodBase method = this.ReflectInfo;
        if (method is MethodInfo)
        {
          return (method as MethodInfo).ReturnType;
        }
        else if (method is ConstructorInfo)
        {
          return typeof(void);
        }
        return null;
      }
    }
    #endregion
    #region Constructors
    public MethodRef() : base() { }
    public MethodRef(MethodBase method) : base(method) { }
    public MethodRef(string identifier,params ParameterRef[] parameters ) : base(identifier, 0) 
    {
      if (parameters != null)
      {
        this.Parameters.AddRange(parameters);
      }
    }
    protected MethodRef(string identifier, int namespacePrefixCount) : base(identifier, namespacePrefixCount) { }
    protected MethodRef(string identifier, int namespacePrefixCount, int classPrefixCount) : base(identifier, namespacePrefixCount, classPrefixCount) { }
    #endregion
    #region Methods
    public override bool IsReferenceOf(object source)
    {
      return source is MethodBase ?
        this.IsMethodRefOf(source as MethodBase):
        base.IsReferenceOf(source);
    }
    /// <summary>
    /// 判别此引用是否指向特定方法。
    /// </summary>
    /// <param name="method">给定方法。</param>
    /// <returns>如果指向，返回true；否则返回false。</returns>
    /// <remarks>此方法帮助符号解析系统进一步的解析方法的不同重载。</remarks>
    public virtual bool IsMethodRefOf(MethodBase method)
    {
      if (method != null)
      {
        if (method == this.referenced) return true;

        bool same = base.IsReferenceOf(method);

        if (same) //If member reference check passed, check parameters.
        {

          ParameterInfo[] parameters = method.GetParameters();

          for (int i = 0; i < parameters.Length; i++)
          {
            using (ParameterRef paramRef = ParameterRef.of(parameters[i],false))
            {
              same = paramRef.Equals(this.Parameters[i]);
            }
            if (!same) break;
          }
        }

        return same;
      }
      return false;
    }
    protected override ReflectRef OnBinding(object source)
    {
      MethodBase method = source as MethodBase;

      if (method != null)
      {

        ParameterInfo[] paramList = method.GetParameters();

        if (paramList != null)
        {
          this.ClearParameters();

          foreach (ParameterInfo param in paramList)
          {
            this.Parameters.Add(ParameterRef.of(param,false));
          }
        }
      }
      return base.OnBinding(method);
    }
    protected override void Dispose(bool disposing)
    {
      if (disposing)
      {
        this.ClearParameters();
        this.parameters = null;
      }
      base.Dispose(disposing);
    }
    protected virtual void ClearParameters()
    {
      foreach (ParameterRef pr in this.Parameters)
      {
        if (pr != null)
        {
          pr.Dispose();
        }
      }

      this.Parameters.Clear();
    }
    #endregion
  }
}
